/*
 * Copyright 2010 Marcin Blazejewski
 *
 * This file is part of Nofate.
 *
 * Nofate is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Nofate is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nofate. If not, see <http://www.gnu.org/licenses/>.
 *
 */


#include "genesis.hpp"
#include "creator.hpp"
#include <abstract/map.hpp>
#include <abstract/thing.hpp>
#include <abstract/typebase.hpp>
#include <abstract/attribute.hpp>
#include <ui/ui.hpp>

#include <iostream>
#include <stdlib.h>
#include <math.h>

//#define GENESIS_TEST
#define DEBUG_DISCOVER_MAP
//#define DEBUG_SEED 1244


#ifdef GENESIS_TEST
#include <SDL/SDL.h>
#include <redeye/font.h>
#include <sstream>
#endif

using namespace std;

/*
void f2_apply(F2 &vmap, int x, int y, float v) {
    if ((x<0)||(x>=vmap.width)||(y<0)||(y>=vmap.height)) return;
    vmap.data[x][y] = vmap.data[x][y] * 0.5
}
*/

void prep_world(AreaMap *world) {
    int i, x, y;
    Thing *t;

    Creator c(*world);

    c.gen_terrain();
    c.add_temple();
    c.render();
    
    /*
    Thing *w2 = tb_spawn("wall", 0x2AAA41CC);
    Thing *f2 = tb_spawn("ruin", 0x2AAA41CC);
    world->terrains.push_back(w2);
    world->terrains.push_back(f2);

    int rx0=x0, ry0=y0;
    Landstruct ruin( Line(0, 0, 5 + (rand() % 4), 0, 0), f2, w2 );
    ruin.add_sub2(0.0);
    ruin.add_sub2(0.5);
    ruin.add_sub2(1.0);
    if (rand() % 100 > 50) rx0 += randv(15, 20);
    else rx0 -= randv(15, 20);
    if (rand() % 100 > 50) ry0 += randv(15, 20);
    else ry0 -= randv(15, 20);
    ruin.render(*world, rx0, ry0);


    ruin = Landstruct( Line(0, 0, 3 + (rand() % 4), 0, 0), floor, w2 );
    ruin.add_sub2(0.0);
    ruin.add_sub2(0.5);
    ruin.add_sub2(1.0);

    rx0 = x0;
    ry0 = y0;
    if (rand() % 100 > 50) rx0 += randv(15, 20);
    else rx0 -= randv(15, 20);
    if (rand() % 100 > 50) ry0 += randv(15, 20);
    else ry0 -= randv(15, 20);
    ruin.render(*world, rx0, ry0);
    */
}


#ifdef GENESIS_TEST        

#define NNN 65
#define RRR 15
void dbg() {
    re_init(NNN, NNN);
    SDL_Event e;
    F2 src(6, 6);
    F2 n(NNN, NNN);
    F2 b(NNN, NNN);
    long seed = 1234;
    
    int N = 3;
    float P = 0.4f;
    float scale = 10;
    bool texture = false;
    bool process = true;
    float flood_range = 0.1;
    unsigned int base[RRR];
    float thr[RRR];

    for (int i = 0; i < RRR; i++) {
        thr[i] = (i+1) * (1.0f / RRR);
    }
    mk_hsv_range(&base[0], 6, 0x38, 0x38, 0x40, 150, 0x90, 0x70);  // gnd
    mk_hsv_range(&base[6], 3, 0x38, 0x62, 140, 170,  110, 130);    // inter
    mk_hsv_range(&base[9], 6, 0x62, 0x62, 0xA0, 0xA0, 130, 45);    // forest
    
    

    while (1) {
        stringstream ss;
        stringstream line1;
        ss << "N=" << N << " P=" << P << " | ";
        ss << thr[0] << " - "  << thr[1] << " - "  << thr[2] << " - "  
           << thr[3] << " - "  << thr[4];

        line1 << "seed:" << seed << " ";

        srand(seed);
        for (int x = 0; x < src.width; x++) {
            for (int y = 0; y < src.height; y++) {
                src.data[x][y] = 1 + rand() % 30;
            }
        }

        // basic terrain
        n.fill(0);
        perlin_noise(src, n, 0, 0, N, P);
        n.normalize();

        // open plain
        n.level(30, 30, flood_range);
        int s = n.count(n.data[30][30]);
        int perc = (s * 100 / (n.width*n.height));
        line1 << "surf=" << s << " (" << perc << "%)";

        // find open spot
        int x0=-1, y0=-1;
        n.find_clearing(n.data[30][30], n.data[30][30], x0, y0);
        
        // draw
        //n.normalize();
        for (int x = 0; x < n.width; x++) {
            for (int y = 0; y < n.height; y++) {
                unsigned int nn = (unsigned int)(n.data[x][y] * 255);
                //unsigned int mm = (unsigned int)m[x][y];
                unsigned int mm =0;
                unsigned int v1 = 0x000000 | (nn/2) | ((mm/2) << 8);
                unsigned int v2 = pick_color( n.data[x][y], base, thr, RRR );
                if (texture)
                    re_putchar(screen, x, y, ' ', 0x0, v2);
                else
                    re_putchar(screen, x, y, ' ', 0x0, v1);
            }
        }

        
        
        re_puts(2, 1, 0xFF0000, 0x0, ss.str().c_str());
        re_puts(2, 2, 0xFF0000, 0x0, line1.str().c_str());
        re_flush();
        
        if (SDL_WaitEvent(&e) == 0) return;

        if (e.type == SDL_QUIT) return;
        else if (e.type == SDL_KEYUP) {
            char ctrl = e.key.keysym.mod & KMOD_CTRL;
            char shift = e.key.keysym.mod & KMOD_SHIFT;

            switch (e.key.keysym.sym) {
            case SDLK_q:  return;
            case SDLK_n:  seed++; break;
            case SDLK_1:  N--; if (N < 1) N = 1; break;
            case SDLK_2:  N++; break;
            case SDLK_3:  P -= 0.1; break;
            case SDLK_4:  P += 0.1; break;
            case SDLK_p:  texture = !texture; break;
            case SDLK_o:  process = !process; break;
            case SDLK_w:  thr[0] += (shift ? 0.01 : -0.01f); break;
            case SDLK_e:  thr[1] += (shift ? 0.01 : -0.01f); break;
            case SDLK_r:  thr[2] += (shift ? 0.01 : -0.01f); break;
            case SDLK_t:  thr[3] += (shift ? 0.01 : -0.01f); break;
            case SDLK_y:  thr[4] += (shift ? 0.01 : -0.01f); break;
            case SDLK_l:  flood_range += (shift ? 0.01 : -0.01f); break;
            }
        }
    }
        
}

#endif


extern "C" int main(int, char**) {
    /* init */
    long seed = time(0) & 0xFFF;

#ifdef DEBUG_SEED
    seed = DEBUG_SEED;
#endif

    cout << "using seed " << seed << endl;
    srand(seed);

#ifdef GENESIS_TEST
    dbg();
    return 0;
#endif

    tb_init();
    AreaMap* world = new AreaMap(100, 100);
    Creature *player = (Creature*)tb_spawn("human"); 
    player->x = 51;
    player->y = 62;

    /* world */

    prep_world(world);
    world->add_thing(player);

    /*
    Thing *t = tb_spawn("torch");
    t->x = 13; t->y = 11;
    world->add_thing(t);

    t = tb_spawn("mail");
    t->x = 12; t->y = 9;
    world->add_thing(t);
    */

    /* interface */

    if (mm_init(100, 100) != 0) exit(-1);
    mm_bind(player, world);
    mm_message("Greetings, engineer. All systems at your command.", 1);

#ifdef DEBUG_DISCOVER_MAP
    // DEBUG: discover all map
    for (int x = 0; x < 100; x++)
        for (int y = 0; y < 100; y++) 
            player->mv->fovmap[x][y] = 3;
#endif

    /* main loop */
    
    char stay_alive = 1;
    while (stay_alive)
    {
        world->tick();
        stay_alive = mm_tick();
    }

    /* cleanup */

    delete world;
    tb_clean();
    mm_end();
    
    return 0;
}


